package com.tools.genxsd.util;

import cn.hutool.core.text.CharSequenceUtil;
import com.tools.genxsd.entity.XElement;
import com.tools.genxsd.entity.XsdDocument;
import com.tools.genxsd.entity.XsdElement;
import com.tools.genxsd.store.TempElementStore;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Objects;
import java.util.function.Consumer;

import static cn.hutool.core.text.StrPool.*;
import static com.tools.genxsd.constant.SysConstant.DOCUMENT;
import static com.tools.genxsd.constant.SysConstant.XSD;

/**
 * @author: zhoubin
 * @date: 2022/11/9
 */
public class ExcelUtil {

    public static void praseExcelToXsdElement(File file) throws Exception {

        // 解析基础组件
        try {
            TempElementStore.praseTemXsdElementList(file);
        } catch (Exception e) {
            System.out.println("文件: " + file.getName() + "的公共组件生成失败");
            throw e;
        }

        praseExcel(file, workbook -> {
            int numberOfSheets = workbook.getNumberOfSheets();
            for (int i = 0; i < numberOfSheets; i++) {
                XSSFSheet sheet = workbook.getSheetAt(i);
                String sheetName = null;

                if (Objects.isNull(sheet)) {
                    break;
                }
                if (CharSequenceUtil.isBlank(sheetName = PatternUtil.splitXsdName(sheet.getSheetName()))) {
                    continue;
                }

                try {
                    XsdElement element = new XsdElement();
                    element.setName(DOCUMENT);
                    element.setMark(DOCUMENT);
                    creatXsdElement(element, sheet, new XElement());

                    XsdDocument xsdDocument = new XsdDocument(element, sheetName);
                    xsdDocument.genXsd(getXsdDirPath(file.getAbsolutePath()) + sheetName + DOT + XSD);
                } catch (Exception e) {
                    System.out.println(sheet.getSheetName() + "解析失败！");
                    throw e;
                }

                SeqUtil.clear();
            }
        });
    }

    /**
     * 拼装xsd文件夹路径
     * @param excelPath
     * @return
     */
    public static String getXsdDirPath(String excelPath) {

        String split = excelPath.contains(SLASH) ? SLASH : BACKSLASH;
        int index = excelPath.lastIndexOf(split);
        return excelPath.substring(0, index + 1) + XSD + split;
    }

    public static void praseExcel(File file, Consumer<XSSFWorkbook> consumer) throws Exception {
        XSSFWorkbook workbook = null;
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            workbook = new XSSFWorkbook(fis);

            consumer.accept(workbook);
        } catch (Exception e) {
            System.out.println("文件: " + file + "解析出错！");
            throw e;
        } finally {
            if (Objects.nonNull(workbook)) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    System.out.println("XSSFWorkbook关闭失败！");
                    throw e;
                }
            }

            if (Objects.nonNull(fis)) {
                try {
                    fis.close();
                } catch (IOException e) {
                    System.out.println("FileInputStream关闭失败！");
                    throw e;
                }
            }
        }
    }

    /**
     * 创建xml树
     * @param element 上一个节点
     * @param sheet Excel的表
     * @param xele 上一个节点的实体类
     * @return
     */
    public static XElement creatXsdElement(XsdElement element, XSSFSheet sheet, XElement xele) {

        // 获取上一节点的行号
        int i = xele.getIndex();

        // 拼装当前节点
        XSSFRow row = sheet.getRow(++i);

        if (Objects.isNull(row)
                || Objects.isNull(row.getCell(2))
                || CharSequenceUtil.isBlank(row.getCell(2).toString())) {

            return null;
        }

        XElement el = new XElement(row);

        // 将增1后的行号放到最新的节点中
        el.setIndex(i);

        // 接收返回的那个节点
        XElement retEl = el;

        // 如果当前的节点的等级大于上一个节点，说明当前节点是上一节点的子节点
        if (el.getLevel() > xele.getLevel()) {

            XsdElement thisEl = element.addElement(el);

            // 返回最新一行的那个节点
            retEl = creatXsdElement(thisEl, sheet, el);

            // 循环至返回来的那个节点跟当前节点不是同级
            while (Objects.nonNull(retEl) && Objects.equals(retEl.getLevel(), el.getLevel())) {
                // 注: 确保在下一个循环时拿到的还是这个节点，需要将行号减一
                el.setIndex(retEl.getIndex() - 1);
                retEl = creatXsdElement(thisEl, sheet, el);
            }
        } else if (Objects.equals(el.getLevel(), xele.getLevel())) {

            // 获取上一个节点的父节点
            XsdElement parent = element.getParent();
            // 将当前节点存入上面找到的父节点中
            XsdElement thisEl = parent.addElement(el);
            retEl = creatXsdElement(thisEl, sheet, el);
        }

        return retEl;
    }

}
